feat: add interactive Try It panel to API docs - #19
Conversation
|
@Nitin-kumar-yadav1307 is attempting to deploy a commit to the Yash Pouranik's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughAdds a new React component TryItPanel and embeds it into the Docs page to allow interactive API requests (configurable x-api-key, path params, method, and body), sending requests to https://api.urbackend.bitbros.in{endpoint} and displaying HTTP status and response text. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser as TryItPanel (UI)
participant API as urBackend API
User->>Browser: Enter x-api-key, fill path params, provide payload (if applicable), click "Send"
Browser->>API: HTTP request to https://api.urbackend.bitbros.in{endpoint} (x-api-key header, JSON body for non-GET)
API-->>Browser: HTTP response (status + body) or error
Browser-->>User: Display HTTP status and response text (or error)
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @frontend/src/components/TryItPanel.jsx:
- Around line 23-25: The catch block in TryItPanel.jsx currently only calls
setResponse(err.message) and leaves the status stale; update the error handling
to also reset the status (e.g., call setStatus('error') or setIsLoading(false)
depending on your status state) so the UI reflects the failed request; modify
the catch that wraps the request (where setResponse is called) to include
setStatus('error') alongside setting the error message.
- Around line 9-26: sendRequest currently sends jsonBody without validating it;
parse jsonBody before making the fetch and if JSON.parse throws, capture the
error and call setStatus(400) and setResponse with a clear validation error
message instead of proceeding; only include the parsed body (stringify it back
or use the original jsonBody) in the fetch when method !== "GET" and parsing
succeeded; keep using setStatus/responses for HTTP and validation flows and
ensure the catch still handles network/fetch errors by setting
setResponse(err.message).
- Line 11: The fetch in TryItPanel.jsx uses a hardcoded API base URL; replace
that hardcoded string at the fetch call (the line with const res = await
fetch(...)) to use an environment variable (VITE_API_BASE_URL via
import.meta.env.VITE_API_BASE_URL) with a sensible fallback, and update usage
throughout the component to build the full URL from this base plus endpoint;
also document/add VITE_API_BASE_URL in your .env files for each environment
(development/staging/production).
🧹 Nitpick comments (3)
frontend/src/components/TryItPanel.jsx (3)
32-37: Consider masking the API key input.The API key is displayed in plain text. While this is a development tool, masking sensitive credentials is a security best practice.
🔐 Proposed enhancement
<input + type="password" className="w-full p-2 mt-1 bg-black border border-zinc-700 rounded" value={apiKey} onChange={(e) => setApiKey(e.target.value)} placeholder="sk_live_xxxxx" />Alternatively, you could add a toggle button to show/hide the key for better UX.
40-48: Consider hiding request body for GET requests.The request body field is always visible, even though line 17 correctly excludes it for GET requests. This might confuse users who see an input field that has no effect.
♻️ Proposed enhancement
+ {method !== "GET" && ( <div className="mb-2"> <label className="text-sm text-zinc-400">Request Body</label> <textarea className="w-full p-2 mt-1 bg-black border border-zinc-700 rounded font-mono" rows={6} value={jsonBody} onChange={(e) => setJsonBody(e.target.value)} /> </div> + )}
50-55: Consider adding a loading state to the Send button.While not critical, a loading indicator would improve UX by showing when a request is in progress and preventing duplicate submissions.
⏳ Proposed enhancement
Add a loading state:
const [status, setStatus] = useState(""); + const [loading, setLoading] = useState(false); async function sendRequest() { + setLoading(true); // ... existing validation ... try { // ... existing fetch logic ... } catch (err) { setStatus("Network Error"); setResponse(err.message); + } finally { + setLoading(false); } }Then update the button:
<button onClick={sendRequest} + disabled={loading} - className="bg-green-500 text-black px-4 py-2 rounded" + className="bg-green-500 text-black px-4 py-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" > - Send Request + {loading ? "Sending..." : "Send Request"} </button>
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src/components/TryItPanel.jsx
🔇 Additional comments (2)
frontend/src/components/TryItPanel.jsx (2)
1-3: LGTM!The component declaration is clean with appropriate defaults for the method parameter.
4-7: LGTM!State initialization with sensible defaults provides good initial UX.
| async function sendRequest() { | ||
| try { | ||
| const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, { | ||
| method, | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| "x-api-key": apiKey, | ||
| }, | ||
| body: method !== "GET" ? jsonBody : null, | ||
| }); | ||
|
|
||
| const data = await res.text(); | ||
| setStatus(res.status); | ||
| setResponse(data); | ||
| } catch (err) { | ||
| setResponse(err.message); | ||
| } | ||
| } |
There was a problem hiding this comment.
Validate JSON before sending the request.
The jsonBody is sent without validation. If the user enters invalid JSON, the request will fail with a confusing error or the server will reject it, providing poor UX.
✅ Proposed fix with JSON validation
async function sendRequest() {
+ // Validate JSON for non-GET requests
+ if (method !== "GET") {
+ try {
+ JSON.parse(jsonBody);
+ } catch (err) {
+ setStatus("400");
+ setResponse(`Invalid JSON: ${err.message}`);
+ return;
+ }
+ }
+
try {
const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function sendRequest() { | |
| try { | |
| const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, { | |
| method, | |
| headers: { | |
| "Content-Type": "application/json", | |
| "x-api-key": apiKey, | |
| }, | |
| body: method !== "GET" ? jsonBody : null, | |
| }); | |
| const data = await res.text(); | |
| setStatus(res.status); | |
| setResponse(data); | |
| } catch (err) { | |
| setResponse(err.message); | |
| } | |
| } | |
| async function sendRequest() { | |
| // Validate JSON for non-GET requests | |
| if (method !== "GET") { | |
| try { | |
| JSON.parse(jsonBody); | |
| } catch (err) { | |
| setStatus("400"); | |
| setResponse(`Invalid JSON: ${err.message}`); | |
| return; | |
| } | |
| } | |
| try { | |
| const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, { | |
| method, | |
| headers: { | |
| "Content-Type": "application/json", | |
| "x-api-key": apiKey, | |
| }, | |
| body: method !== "GET" ? jsonBody : null, | |
| }); | |
| const data = await res.text(); | |
| setStatus(res.status); | |
| setResponse(data); | |
| } catch (err) { | |
| setResponse(err.message); | |
| } | |
| } |
🤖 Prompt for AI Agents
In @frontend/src/components/TryItPanel.jsx around lines 9 - 26, sendRequest
currently sends jsonBody without validating it; parse jsonBody before making the
fetch and if JSON.parse throws, capture the error and call setStatus(400) and
setResponse with a clear validation error message instead of proceeding; only
include the parsed body (stringify it back or use the original jsonBody) in the
fetch when method !== "GET" and parsing succeeded; keep using
setStatus/responses for HTTP and validation flows and ensure the catch still
handles network/fetch errors by setting setResponse(err.message).
|
|
||
| async function sendRequest() { | ||
| try { | ||
| const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, { |
There was a problem hiding this comment.
Move API base URL to environment configuration.
The API base URL is hardcoded, which prevents the component from adapting to different environments (development, staging, production).
🔧 Proposed fix using environment variable
- const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, {
+ const res = await fetch(`${import.meta.env.VITE_API_BASE_URL || 'https://api.urbackend.bitbros.in'}${endpoint}`, {Then add VITE_API_BASE_URL to your .env files for each environment.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const res = await fetch(`https://api.urbackend.bitbros.in${endpoint}`, { | |
| const res = await fetch(`${import.meta.env.VITE_API_BASE_URL || 'https://api.urbackend.bitbros.in'}${endpoint}`, { |
🤖 Prompt for AI Agents
In @frontend/src/components/TryItPanel.jsx at line 11, The fetch in
TryItPanel.jsx uses a hardcoded API base URL; replace that hardcoded string at
the fetch call (the line with const res = await fetch(...)) to use an
environment variable (VITE_API_BASE_URL via import.meta.env.VITE_API_BASE_URL)
with a sensible fallback, and update usage throughout the component to build the
full URL from this base plus endpoint; also document/add VITE_API_BASE_URL in
your .env files for each environment (development/staging/production).
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/pages/Docs.jsx (1)
105-114: Add a security acknowledgement to the TryItPanel component, or gate it behind an opt-in flag.The Intro tab explicitly warns (lines 109-114): "❌ NEVER use this key in client-side code (frontend)". However, the TryItPanel component (lines 257-258, and component at
frontend/src/components/TryItPanel.jsx) directly asks users to paste their admin-levelx-api-keyinto a browser input field and makes unguarded API requests from the browser.This creates a direct contradiction. If this in-browser testing is intentional, the TryItPanel must include an explicit security acknowledgement (e.g., "This runs in your browser; your key is never sent to our servers; treat it as a secret; do not use on shared machines") or be gated behind an opt-in toggle / environment-specific flag.
Additionally, the component uses a hardcoded base URL (
https://api.urbackend.bitbros.in) instead of the importedAPI_URLconfig, risking inconsistency across environments.
🤖 Fix all issues with AI agents
In @frontend/src/pages/Docs.jsx:
- Around line 3-4: Docs.jsx imports API_URL but TryItPanel currently uses a
hard-coded domain; update Docs.jsx to pass API_URL into TryItPanel (e.g., as a
baseUrl prop) and modify TryItPanel to accept and use that prop (or import
API_URL directly) when building request URLs instead of the fixed
"https://api.urbackend.bitbros.in"; ensure TryItPanel uses the passed baseUrl
when composing requests and remove the hard-coded domain so local/staging
environments follow API_URL.
🧹 Nitpick comments (1)
frontend/src/pages/Docs.jsx (1)
247-258: Consider aligning the “Try It” example with the documented:collectionNameplaceholder.Right now the code sample documents
/api/data/:collectionNamebut the interactive panel uses/api/data/products. That’s fine as an example, but it may confuse users about whether they should replace:collectionNameor useproductsliterally. A small label (“Example uses collection: products”) or making the collection editable would reduce ambiguity.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src/pages/Docs.jsx
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/Docs.jsx (1)
frontend/src/components/TryItPanel.jsx (1)
TryItPanel(3-65)
| import { API_URL } from '../config'; | ||
| import TryItPanel from "../components/TryItPanel.jsx"; |
There was a problem hiding this comment.
Avoid base-URL drift: ensure TryItPanel uses API_URL (not a hard-coded domain).
Docs.jsx already centralizes the base URL via API_URL (Line 3), but TryItPanel (per provided snippet) builds requests from a fixed https://api.urbackend.bitbros.in. That’s likely to break local/staging docs and makes the docs page inconsistent. Prefer passing API_URL into TryItPanel (or have TryItPanel import the same config) and only pass endpoint from Docs.jsx.
Proposed change (requires updating TryItPanel to accept/use `baseUrl`)
- <TryItPanel endpoint="/api/data/products" method="POST" />
+ <TryItPanel baseUrl={API_URL} endpoint="/api/data/products" method="POST" />Also applies to: 257-258
🤖 Prompt for AI Agents
In @frontend/src/pages/Docs.jsx around lines 3 - 4, Docs.jsx imports API_URL but
TryItPanel currently uses a hard-coded domain; update Docs.jsx to pass API_URL
into TryItPanel (e.g., as a baseUrl prop) and modify TryItPanel to accept and
use that prop (or import API_URL directly) when building request URLs instead of
the fixed "https://api.urbackend.bitbros.in"; ensure TryItPanel uses the passed
baseUrl when composing requests and remove the hard-coded domain so
local/staging environments follow API_URL.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @frontend/src/components/TryItPanel.jsx:
- Around line 46-48: The catch block currently sets setResponse(err.message) and
leaves status unchanged, causing stale status and inconsistent handling versus
validation errors; change the catch to setError(err.message) (matching
validation error usage), clear any previous response with setResponse('') and
reset status (e.g., setStatus(null) or ''), so network errors use the same error
state and the displayed HTTP status is cleared when an error occurs.
- Around line 11-17: buildEndpoint currently inserts raw param values into the
URL which allows spaces and special characters to break the URL; update the
replacement logic in buildEndpoint to URL-encode each path param value (use
encodeURIComponent on params[key] or equivalent) before calling url.replace, and
guard against null/undefined params by coercing to string so replacements always
produce a valid, encoded URL.
🧹 Nitpick comments (2)
frontend/src/components/TryItPanel.jsx (2)
57-65: Consider adding label-input association for accessibility.The label is not programmatically associated with the input field. Adding
htmlForandidattributes improves screen reader support.Suggested improvement
<div style={{ marginBottom: "1rem" }}> - <label className="form-label">x-api-key</label> + <label className="form-label" htmlFor="tryit-api-key">x-api-key</label> <input + id="tryit-api-key" className="input-field" value={apiKey} onChange={(e) => setApiKey(e.target.value)} placeholder="YOUR API KEY" /> </div>
114-116: Consider adding a loading state to prevent double-clicks and improve UX.Without a loading indicator, users may click "Send Request" multiple times or not realize a request is in progress.
Suggested approach
Add a
loadingstate and disable the button while the request is pending:const [params, setParams] = useState({}); +const [loading, setLoading] = useState(false); async function sendRequest() { if (!apiKey || apiKey.trim() === "") { setError("You need an API key. Go to Dashboard → Create Project → Copy API key."); return; } setError(""); + setLoading(true); try { // ... fetch logic } catch (err) { - setResponse(err.message); + setError(`Network error: ${err.message}`); + setResponse(""); + setStatus(""); + } finally { + setLoading(false); } }Then update the button:
-<button onClick={sendRequest} className="btn btn-primary"> - Send Request +<button onClick={sendRequest} className="btn btn-primary" disabled={loading}> + {loading ? "Sending..." : "Send Request"} </button>
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/src/components/TryItPanel.jsxfrontend/src/pages/Docs.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/pages/Docs.jsx
🔇 Additional comments (5)
frontend/src/components/TryItPanel.jsx (5)
1-9: LGTM!State initialization and component signature are appropriate. Default method of
"POST"aligns with the PR objective of testing POST requests.
66-86: LGTM!Dynamic path parameter extraction using regex and conditional rendering is implemented correctly. The optional chaining on
.map()safely handles cases where no params exist.
88-98: LGTM!Conditional rendering for non-GET methods is correct. The monospace font choice is appropriate for JSON editing.
100-112: LGTM!Error display is appropriately styled and conditionally rendered.
118-135: LGTM!Response display with status code and pre-formatted output meets the PR objective of displaying live responses including status code and body.
| function buildEndpoint() { | ||
| let url = endpoint; | ||
| Object.keys(params).forEach(key => { | ||
| url = url.replace(`:${key}`, params[key]); | ||
| }); | ||
| return url; | ||
| } |
There was a problem hiding this comment.
URL-encode path parameters to prevent malformed URLs.
User-provided parameter values containing special characters (spaces, slashes, etc.) will produce invalid URLs or cause unintended routing behavior.
Proposed fix
function buildEndpoint() {
let url = endpoint;
Object.keys(params).forEach(key => {
- url = url.replace(`:${key}`, params[key]);
+ url = url.replace(`:${key}`, encodeURIComponent(params[key] || ""));
});
return url;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function buildEndpoint() { | |
| let url = endpoint; | |
| Object.keys(params).forEach(key => { | |
| url = url.replace(`:${key}`, params[key]); | |
| }); | |
| return url; | |
| } | |
| function buildEndpoint() { | |
| let url = endpoint; | |
| Object.keys(params).forEach(key => { | |
| url = url.replace(`:${key}`, encodeURIComponent(params[key] || "")); | |
| }); | |
| return url; | |
| } |
🤖 Prompt for AI Agents
In @frontend/src/components/TryItPanel.jsx around lines 11 - 17, buildEndpoint
currently inserts raw param values into the URL which allows spaces and special
characters to break the URL; update the replacement logic in buildEndpoint to
URL-encode each path param value (use encodeURIComponent on params[key] or
equivalent) before calling url.replace, and guard against null/undefined params
by coercing to string so replacements always produce a valid, encoded URL.
| } catch (err) { | ||
| setResponse(err.message); | ||
| } |
There was a problem hiding this comment.
Inconsistent error handling leaves stale status displayed.
Network errors are assigned to response state while validation errors use error state. Additionally, status is not cleared, so users may see a previous request's status code alongside the new error message—creating a confusing UX.
Proposed fix
} catch (err) {
- setResponse(err.message);
+ setError(`Network error: ${err.message}`);
+ setResponse("");
+ setStatus("");
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (err) { | |
| setResponse(err.message); | |
| } | |
| } catch (err) { | |
| setError(`Network error: ${err.message}`); | |
| setResponse(""); | |
| setStatus(""); | |
| } |
🤖 Prompt for AI Agents
In @frontend/src/components/TryItPanel.jsx around lines 46 - 48, The catch block
currently sets setResponse(err.message) and leaves status unchanged, causing
stale status and inconsistent handling versus validation errors; change the
catch to setError(err.message) (matching validation error usage), clear any
previous response with setResponse('') and reset status (e.g., setStatus(null)
or ''), so network errors use the same error state and the displayed HTTP status
is cleared when an error occurs.
yash-pouranik
left a comment
There was a problem hiding this comment.
Thanky for the PR @Nitin-kumar-yadav1307
Feel free to contribute in future, all the best.
Fixes #8
What this PR adds
Adds an interactive “Try It Out” panel to the API documentation so developers can test endpoints directly from the docs using their API key.
Why
This improves developer experience by allowing users to validate requests, headers, and payloads without leaving the documentation.
What’s included
How to test
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.